package com.asa.c;

public class C {

	
	/**
	 * 案例实战
	 * 
	 * 设置启动参数，
	 * -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=d:\student.hprof
	 * 
	 * 
	 * MAT打开dump，即student.hprof文件
	 * 
	 * Tomcat是最常用的Java Servlet容器之一，同时也可以当做单独的Web服务器使用。Tomcat本身使
		用Java实现，并运行于Java虚拟机之上。在大规模请求时，Tomcat 有可能会因为无法承受压力而发生
		内存溢出错误。这里根据一个被压垮的Tomcat的堆快照文件，来分析Tomcat在崩溃时的内部情况。
	 * 
	 */
	
	
	/**
	 * 
	 * 内存溢出专题
	 * 
	 * 
	 * 可达性分析算法来判断对象是否是不再使用的对象，本质都是判断一个对象是否还被引用。那么对于
		这种情况下，由于代码的实现不同就会出现很多种内存泄漏问题(让JVM误以为此对象还在引用中，无
		法回收，造成内存泄漏)。
I

	 * 
	 * 
	 * 内存泄漏与内存溢出的关系:
		1.内存泄漏(memory leak )
		申请了内存用完了不释放，比如一共有1024M 的内存，分配了521M 的内存一直不回收， 那么可以
		用的内存只有521M了，仿佛泄露掉了一部分;
		通俗一点讲的话，内存泄漏就是[占着茅坑不拉shi]。
		2.内存溢出(out of memory)
		申请内存时，没有足够的内存可以使用;
		通俗一一点儿讲，-一个厕所就三个坑，有两个站着茅坑不走的(内存泄漏)，剩下最后一个坑，厕所表
		示接待压力很大，这时候一-下子来了两个人，坑位(内存)就不够了，内存泄漏变成内存溢出了。

	 * 
	 * 
	 * 
	 * 
	 * 泄漏的分类
		经常发生:发生内存泄露的代码会被多次执行，每次执行，泄露一块内存;
		偶然发生:在某些特定情况下才会发生;
		一次性:发生内存泄露的方法只会执行-次;
		隐式泄漏:一直占着内存不释放，直到执行结束;严格的说这个不算内存泄漏，因为最终释放掉了，
		但是如果执行时间特别长，也可能会导致内存耗尽。

	 * 
	 * 
	 * 1-静态集合类
			静态集合类，如HashMap、 LinkedList等等。 如果这些容器为静态的，那么它们的生命周期与JVM程
			序一致，则容器中的对象在程序结束之前将不能被释放，从而造成内存泄漏。简单而言，长生命周期的
			对象持有短生命周期对象的引用，尽管短生命周期的对象不再使用，但是因为长生命周期对象持有它的
			引用而导致不能被回收。

	 * 
	 * 2- 单例模式
			单例模式，和静态集合导致内存泄露的原因类似，因为单例的静态特性，它的生命周期和JVM的生命
			周期一样长，所以如果单例对象如果持有外部对象的引用，那么这个外部对象也不会被回收，那么就会
			造成内存泄漏。[

	 * 
	 * 3-内部类持有外部类
			内部类持有外部类，如果--个外部类的实例对象的方法返回工一个内部类的实例对象。
			这个内部类对象被长期引用了，即使那个外部类实例对象不再被使用，但由于内部类持有外部类的实例
			对象，这个外部类对象将不会被垃圾回收，这也会造成内存泄漏。

	 * 
	 * 
	 * 4-各种连接，如数据库连接、网络连接和I0连接等
			各种连接，如数据库连接、网络连接和IO连接等。
			在对数据库进行操作的过程中，首先需要建立与数据库的连接，当不再使用时，需要调用close方法来
			释放与数据库的连接。只有连接被关闭后，垃圾回收器才会回收对应的对象。
			否则，如果在访问数据库的过程中，对Connection、 Statement或ResultSet 不显性地关闭，将会造
			成大量的对象无法被回收，从而引起内存泄漏。

	 * 
	 * 
	 * 
	 * 
	 * 5-变量不合理的作用域
			变量不合理的作用域。T般而言，一个变量的定义的作用范围大于其使用范围，很有可能会造成内存泄
			漏。另一方面，如果没有及时地把对象设置为null,很有可能导致内存泄漏的发生。
			public class UsingRandom {
			private String msg;
			public void receiveMsg(){
			readFromNet();//从网络中接受数据保存到msg中
			saveDB();//把msg保存到数据库
			}
			}
			如上面这个伪代码，通过readFromNet 方法把接受的消息保存在变量msg中，然后调用saveDB方法把
			msg的内容保存到数据库中，此时msg已经就没用了，由于msg的生命周期与对象的生命周期相同，此
			时msg还不能回收，因此造成了内存泄漏。
			实际上这个msg变量可以放在receiveMsg方法内部，当方法使用完，那么msg的生命周期也就结束，
			此时就可以回收了。还有一种方法，在使用完msg后，把msg设 置为null，这样垃圾回收器也会回收
			msg的内存空间。

			

	 * 
	 * 
	 * 
	 * 6-改变哈希值
			改变哈希值，当一个对象被存储进HashSet集合重以后，就不能修改这个对象中的那些参与计算哈希值
			的字段了。
			否则，对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了，在这种情况下，即使在
			contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象，也将返回找不到对象的
			结果，这也会导致无法从HashSet集合中单独删除当前对象，造成内存泄漏。
			这也是String 为什么被设置成了不可变类型，我们可以放心地把String 存入HashSet， 或者把
			String当做HashMap的key值;
			当我们想把自己定义的类保存到散列表的时候，需要保证对象的hashCode不可变。

	 * 
	 * 
	 * 7-缓存泄漏
			内存泄漏的另一个常见来源是缓存，一 旦 你把对象引用放入到缓存中，他就很容易遗忘。比如:主前项
			目在一次上线的时候，应用启动奇慢直到夯死，就是因为代码中会加载一个表中的数据到缓存(内存)
			中，测试环境只有几百条数据，但是生产环境有几百万的数据。
			对于这个问题，可以使用WeakHashMap代表缓存， 此种Map的特点是，当除了自身有对key的引用
			外，此key没有其他引用那么此map会自动丢弃此值。

	 * 
	 * 
	 * 
	 * 8-监听器和回调
			内存泄漏第三个常见来源是监听器和其他回调，如果客户端在你实现的API中注册回调，却没有显示的
			取消，那么就会积聚。
			需要确保回调立即被当作垃圾回收的最佳方法是只保存它的弱引用，例如将他们保存成为
			WeakHashMap中的键。

	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */
	
	
	
	
	
	
	
	
}
